// This file is licensed under the Elastic License 2.0. Copyright 2021 StarRocks Limited.
package com.starrocks.sql.optimizer.operator.physical;

import com.google.common.base.Objects;
import com.starrocks.catalog.TableFunction;
import com.starrocks.sql.optimizer.OptExpression;
import com.starrocks.sql.optimizer.OptExpressionVisitor;
import com.starrocks.sql.optimizer.base.ColumnRefSet;
import com.starrocks.sql.optimizer.operator.OperatorType;
import com.starrocks.sql.optimizer.operator.OperatorVisitor;

public class PhysicalTableFunctionOperator extends PhysicalOperator {
    private final TableFunction fn;
    //ColumnRefSet represent output by table function
    private final ColumnRefSet fnResultColumnRefSet;
    //External column ref of the join logic generated by the table function
    private final ColumnRefSet outerColumnRefSet;
    //table function input parameters
    private final ColumnRefSet fnParamColumnRefSet;

    public PhysicalTableFunctionOperator(ColumnRefSet fnResultColumnRefSet, TableFunction fn,
                                         ColumnRefSet fnParamColumnRefSet, ColumnRefSet outerColumnRefSet) {
        super(OperatorType.PHYSICAL_TABLE_FUNCTION);
        this.fnResultColumnRefSet = fnResultColumnRefSet;
        this.fn = fn;
        this.fnParamColumnRefSet = fnParamColumnRefSet;
        this.outerColumnRefSet = outerColumnRefSet;
    }

    public ColumnRefSet getOutputColumns() {
        ColumnRefSet outputColumns = (ColumnRefSet) outerColumnRefSet.clone();
        outputColumns.union(fnResultColumnRefSet);
        return outputColumns;
    }

    public ColumnRefSet getFnResultColumnRefSet() {
        return fnResultColumnRefSet;
    }

    public TableFunction getFn() {
        return fn;
    }

    public ColumnRefSet getParamColumnRefs() {
        return fnParamColumnRefSet;
    }

    public ColumnRefSet getOuterColumnRefSet() {
        return outerColumnRefSet;
    }

    @Override
    public <R, C> R accept(OperatorVisitor<R, C> visitor, C context) {
        return visitor.visitPhysicalTableFunction(this, context);
    }

    @Override
    public <R, C> R accept(OptExpressionVisitor<R, C> visitor, OptExpression optExpression, C context) {
        return visitor.visitPhysicalTableFunction(optExpression, context);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        PhysicalTableFunctionOperator that = (PhysicalTableFunctionOperator) o;
        return Objects.equal(fn, that.fn) && Objects.equal(fnResultColumnRefSet, that.fnResultColumnRefSet) &&
                Objects.equal(outerColumnRefSet, that.outerColumnRefSet) &&
                Objects.equal(fnParamColumnRefSet, that.fnParamColumnRefSet);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(fn, fnResultColumnRefSet, outerColumnRefSet, fnParamColumnRefSet);
    }
}